#include "SessionHandler.h"

SessionHandler::SessionHandler(int id, SOCKET socket, MultiplayerGameServer* server)
{
	this->id = id;
	this->socket = socket;
	this->server = server;
	this->_isInitialized = false;
	
	_isInvalidated = true;
	
}

SessionHandler::~SessionHandler(void)
{
}

int SessionHandler::getId(void)
{
	return id;
}

SOCKET SessionHandler::getSocket(void)
{
	return socket;
}

DWORD SessionHandler::run(void)
{
	return handleSession();
}

int SessionHandler::handleSession(void)
{
	cout << "Session handling started on socket " << socket << "." << endl;

	char recvbuf[1024];
    int recvbuflen = 1024;
	bool end =false;
	int receiveResult;
	char* pBuf;
    do
    {
        receiveResult = recv(socket, recvbuf, recvbuflen, 0);
		cout << "In session handler received:" <<receiveResult<<" bytes."<< endl;
        if (receiveResult > 0)
        {
			GameEvent* gameEvent = new GameEvent();
			ByteBuffer* buffer = new ByteBuffer();
			buffer->put(recvbuf, receiveResult);
			gameEvent->unmarshal(buffer);
			if(gameEvent->getType()==EVENT_GAME_SESSION_END)
				end=true;
			if(!this->_isInitialized || end){
				
				
				processEvent(gameEvent);
				
				delete buffer;
			}else{
				int dataReceived = receiveResult;
				pBuf= recvbuf;
				while (dataReceived >0){
				int tamanio = atoi(pBuf);
				stringstream ss;
				ss << tamanio;	
				int sizeOfTam=(int)strlen(ss.str().c_str());
				pBuf+= sizeOfTam;
				dataReceived= dataReceived - sizeOfTam;
				if(dataReceived >= tamanio){
				ByteBuffer* buffer = new ByteBuffer();
				buffer->put(pBuf, tamanio);
				gameEvent->unmarshal(buffer);
				processEvent(gameEvent);
				pBuf+= tamanio;
				dataReceived= dataReceived-tamanio;
				delete buffer;				  
				}
				}
				
				delete gameEvent;
			}

			
        }
        else if (receiveResult == 0)
        {
            cout << "Connection closed" << endl;
        }
        else
        {
			int errorCode = WSAGetLastError();
            cout << "recv failed with error: " << errorCode << endl;
			if (errorCode == 10054 || errorCode == 10060)
			{
				Log::getInstance()->info("Processing end game session event.");
				GameEvent* ev = new GameEvent();
				ev->setCode(4);
				ev->setId(this->id);
				this->server->updateSceneState(ev);
				this->update(ev);
				_isInvalidated = true;
			}
        }
    } while (receiveResult > 0);

	return 0;
}

void SessionHandler::update(GameEvent* event)
{
	ByteBuffer* buffer = event->marshal();
	int remoteSendResult = send(socket, buffer->get(), buffer->size(), 0);
	if (remoteSendResult == SOCKET_ERROR)
	{
		cout << "Error forwarding message." << endl;
	}
}

bool SessionHandler::isInvalidated(void)
{
	return _isInvalidated;
}

void SessionHandler::processEvent(GameEvent* gameEvent)
{
	Log::getInstance()->info(gameEvent->toString());

	switch(gameEvent->getType())
	{
	case EVENT_UNDEFINED:
		{
			//server->updateSceneState(gameEvent);
			Log::getInstance()->info("Unable to process undefined event; this event is discarded.");
		}
		break;
	case EVENT_GAME_SESSION_BEGIN:
		{
			Log::getInstance()->info("Processing begin game session event.");
			sendSessionId();
			sendBackground(server->getSceneState()->getBackgroundPath());
			sendSceneState();
			GameEvent* ev = new GameEvent();
			ev->setCode(5);
			ev->setX(200);
			ev->setY(432);
			ev->setAngle(0);
			ev->setName(gameEvent->getSource());
			ev->setId(this->id);
			this->server->updateSceneState(ev);
			this->update(ev);
			_isInitialized = true;
			_isInvalidated = false;
		}
		break;
	case EVENT_GAME_SESSION_END:
		{
			Log::getInstance()->info("Processing end game session event.");
			GameEvent* ev = new GameEvent();
			ev->setCode(4);
			ev->setId(this->id);
			this->server->updateSceneState(ev);
			this->update(ev);
			_isInvalidated = true;
		}
		break;
	case EVENT_GAME_SESSION_CLIENTSERVER:
		{
			Log::getInstance()->info("Processing begin session clientserver.");
			sendSceneState();
			GameEvent* ev = new GameEvent();
			ev->setCode(5);
			ev->setX(200);
			ev->setY(432);
			ev->setAngle(23);
			ev->setName(gameEvent->getSource());
			ev->setId(this->id);
			this->server->updateSceneState(ev);
			this->update(ev);
			
			_isInvalidated = false;
		}
		break;
		case EVENT_MOVE:
		{
			server->updateSceneState(gameEvent);
			Log::getInstance()->info("Movement event received.");
		}
		break;
	default:
		{
		}
	}
	//server->update(gameEvent);
}

void SessionHandler::sendSessionId(void)
{
	Log::getInstance()->info("Sending session id.");
}

void SessionHandler::sendBackground(string filepath)
{
	Log::getInstance()->info("Sending game background.");

	ifstream file;
	ifstream::pos_type fileSize = 0;
	char readBuffer[2048];
	char sendBuffer[1024];

	char* startFileCmd = "STARTFILE";
	char* endFileCmd = "ENDFILE";

	ifstream::pos_type readSize = 2048;
	int sendSize = 1024;
	ifstream::pos_type bytesInReadBuffer = 0;
	ifstream::pos_type zeroBytes = 0;
	int bytesInSendBuffer = 0;
	ifstream::pos_type totalBytesRead = 0;

	size_t index = filepath.find_last_of("\\");
	string filename = filepath.substr(index+1);

	file.open(filepath, ios::in | ios::binary | ios::ate);
	if (file.is_open())
	{
		send(socket, startFileCmd, (int)strlen(startFileCmd), 0);
		cout << "Sent STARTFILE command." << endl;
		Sleep(100);
		send(socket, filename.c_str(), (int)strlen(filename.c_str()), 0);
		cout << "Sent background file name." << endl;
		Sleep(100);
		fileSize = file.tellg();
		cout << "File size: " << fileSize << endl;
		file.seekg(0, ios::beg);
		int bytesSent = 0;
		int lastBytesSent = 0;
		int totalBytesSent = 0;
		while (file.good() && totalBytesRead < fileSize)
		{
			if (bytesInReadBuffer <	1024 && totalBytesRead < fileSize)
			{
				if (bytesInReadBuffer != zeroBytes)
				{
					memcpy(readBuffer, readBuffer+(readSize-bytesInReadBuffer), bytesInReadBuffer);
				}

				if (fileSize-totalBytesRead < readSize-bytesInReadBuffer)
				{
					file.read(readBuffer+bytesInReadBuffer, fileSize-totalBytesRead);
					bytesInReadBuffer += (fileSize-totalBytesRead);
					totalBytesRead = fileSize;
				}
				else
				{
					file.read(readBuffer+bytesInReadBuffer, readSize-bytesInReadBuffer);
					totalBytesRead += (readSize-bytesInReadBuffer);
					bytesInReadBuffer = readSize;
				}
			}

			if (bytesInSendBuffer < 512 && bytesInReadBuffer > 0)
			{
				if (bytesInSendBuffer != zeroBytes)
				{
					memcpy(sendBuffer, sendBuffer+(sendSize-bytesInSendBuffer), bytesInSendBuffer);
				}

				if (bytesInReadBuffer < sendSize-bytesInSendBuffer)
				{
					memcpy(sendBuffer+bytesInSendBuffer, readBuffer, bytesInReadBuffer);//+(readSize-bytesInReadBuffer)
					bytesInSendBuffer += bytesInReadBuffer;
					bytesInReadBuffer = 0;
				}
				else
				{
					memcpy(sendBuffer+bytesInSendBuffer, readBuffer+(readSize-bytesInReadBuffer), sendSize-bytesInSendBuffer);
					bytesInReadBuffer -= (sendSize-bytesInSendBuffer);
					bytesInSendBuffer = sendSize;
				}
				bytesSent = 0;
			}

			if (bytesInSendBuffer > 0)
			{
				lastBytesSent = send(socket, sendBuffer+bytesSent, bytesInSendBuffer, 0);//sendSize-bytesSent, 0);
				if (lastBytesSent == SOCKET_ERROR)
				{
					cout << "send failed with error: " << WSAGetLastError() << endl;
				}
				else
				{
					cout << "Sent " << lastBytesSent << " bytes." << endl;
				}
			}
			bytesInSendBuffer -= lastBytesSent;
			bytesSent += lastBytesSent;
			totalBytesSent += lastBytesSent;
		}
		file.close();
		cout << "Total bytes read from file: " << totalBytesRead << endl;
		cout << "Total bytes sent: " << totalBytesSent << endl;
		Sleep(200);
		send(socket, endFileCmd, (int)strlen(endFileCmd), 0);
		cout << "Sent ENDFILE command" << endl;
		Sleep(200);
	}
	else
	{
		cout << "Unable to open file." << endl;
	}
}

void SessionHandler::sendSceneState(void)
{
	
	char sendBuffer[1024];
	int totalBytesRead=0;
	int bytesInReadBuffer=0;
	int bytesToSend;
	int serialSize=0;
	int remainingBytes;
	int totalBytesSent=0;
	char* startFileCmd = "STARTSCENE";
	char* endFileCmd = "ENDSCENE";
	ByteBuffer* b;
	b=this->server->getSceneState()->marshal();
	serialSize = b->size();
	remainingBytes = serialSize;
	const char* readBuffer = b->get();
	Log::getInstance()->info("Sending scene state.");
	stringstream ss;
	ss << serialSize;	
	send(socket, ss.str().c_str(), (int)strlen(ss.str().c_str()), 0);
	cout << "Sent Scene size:" << ss.str()<< endl;
	cout << "Sent Scene size with lenght" << (int)strlen(ss.str().c_str())<< endl;
	Sleep(100);

	while (totalBytesSent < serialSize)
		{
			//if (bytesInReadBuffer <	1024 && totalBytesRead < serialSize)
			if(serialSize < 1024 )
			{
				int remoteSendResult = send(socket, b->get(), b->size(), 0);
				if (remoteSendResult == SOCKET_ERROR)
				{
					cout << "Error forwarding message." << endl;
				}else{
					cout << "Sent:"<< remoteSendResult <<" bytes." << endl;
				}
				totalBytesSent += remoteSendResult;
				Sleep(200);
			}else{
				if(remainingBytes > 1024){
					bytesToSend=1024;
				}else{
					bytesToSend=remainingBytes;
				}
				memcpy(sendBuffer, readBuffer+(totalBytesSent), bytesToSend);
				int remoteSendResult = send(socket, sendBuffer, bytesToSend, 0);
				if (remoteSendResult == SOCKET_ERROR)
				{
					cout << "Error forwarding message." << endl;
				}else{
					cout << "Sent:"<< remoteSendResult <<" bytes." << endl;
				}
				totalBytesSent += remoteSendResult;
				remainingBytes -= bytesToSend;
				Sleep(200);

			}
			
		//	if (bytesInSendBuffer > 0)
		//	{
		//		lastBytesSent = send(socket, sendBuffer+bytesSent, bytesInSendBuffer, 0);//sendSize-bytesSent, 0);
		//		if (lastBytesSent == SOCKET_ERROR)
		//		{
		//			cout << "send failed with error: " << WSAGetLastError() << endl;
		//		}
		//		else
		//		{
		//			cout << "Sent " << lastBytesSent << " bytes." << endl;
		//		}
		//	}
		//	bytesInSendBuffer -= lastBytesSent;
		//	bytesSent += lastBytesSent;
		//	totalBytesSent += lastBytesSent;
		//}
	}
	Sleep(200);
	char recvbuf[1024];
    int recvbuflen = 1024;
	int receiveResult;
	char* pBuf;
	bool sceneReceived = false;
	string bytes = "";
	string command = "";
	string startFileCommand = "SCENERECIBIDO";
	string endFileCommand = "ENDSCENE";
	cout << "Sent Scene of "<<totalBytesSent<<" bytes." << endl;
	
	recv(socket, recvbuf, recvbuflen, 0);
	command = bytes.append(recvbuf).substr(0, startFileCommand.length());

	if (command.compare(startFileCommand) == 0){
		sceneReceived = true;
		cout << "Received SCENERECEIVED confirmation." <<  endl;	
	}

	/*send(socket, endFileCmd, (int)strlen(endFileCmd), 0);
		cout << "Sent ENDSCENE command" << endl;*/
}
